using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using HslCommunication;

namespace HslCommunicationEx.SerialCom
{
	public abstract class BaseSerialPort
	{
		public delegate void RcvData(byte[] rcvData);

		protected SerialPort _serialPort;

		protected OperateResult IsPortValid
		{
			get
			{
				OperateResult operateResult = new OperateResult();
				if (this._serialPort == null)
				{
					operateResult.Message = "please initialize first";
					return operateResult;
				}
				if (!this._serialPort.IsOpen)
				{
					operateResult.Message = "please open port first";
					return operateResult;
				}
				operateResult.IsSuccess = true;
				return operateResult;
			}
		}

		public event RcvData rcvDataEventHandler;

		public OperateResult ComInitial(string sPortName, int baudrate, int dataBits, string parity, int timeOut = 3000)
		{
			OperateResult operateResult = new OperateResult();
			try
			{
				if (BaseSerialPort.GetPorts().All((string x) => x.ToLower() != sPortName.ToLower()))
				{
					operateResult.Message = sPortName + " not exist!";
					return operateResult;
				}
				this._serialPort = new SerialPort(sPortName, baudrate, this.ReturnParity(parity), dataBits, StopBits.One);
				this._serialPort.ReadTimeout = timeOut;
				operateResult = this.OpenPort();
				return operateResult;
			}
			catch (Exception ex)
			{
				operateResult.Message = ex.Message;
				return operateResult;
			}
		}

		protected Parity ReturnParity(string enterParity)
		{
			return enterParity.ToUpper() switch
			{
				"NONE" => Parity.None, 
				"ODD" => Parity.Odd, 
				"EVEN" => Parity.Even, 
				_ => Parity.None, 
			};
		}

		protected virtual void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
		{
			OperateResult<byte[]> operateResult = new OperateResult<byte[]>();
			if (e.EventType != SerialData.Chars)
			{
				operateResult.Message = "e.EventType != SerialData.Chars";
				this.AfterRcvCompleted(operateResult);
			}
			else if (this._serialPort.BytesToRead <= 0)
			{
				DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(15, 1);
				defaultInterpolatedStringHandler.AppendLiteral("BytesToRead:");
				defaultInterpolatedStringHandler.AppendFormatted(this._serialPort.BytesToRead);
				defaultInterpolatedStringHandler.AppendLiteral("<=0");
				operateResult.Message = defaultInterpolatedStringHandler.ToStringAndClear();
				this.AfterRcvCompleted(operateResult);
			}
			else
			{
				this.AfterRcvCompleted(this.Read());
			}
		}

		protected virtual void AfterRcvCompleted(OperateResult<byte[]> rcvBuf)
		{
		}

		protected OperateResult OpenPort()
		{
			OperateResult operateResult = new OperateResult();
			try
			{
				if (this._serialPort == null)
				{
					operateResult.Message = "please initialize first!";
					return operateResult;
				}
				if (!this._serialPort.IsOpen)
				{
					this._serialPort.Open();
				}
			}
			catch (Exception ex)
			{
				operateResult.Message = ex.Message;
				return operateResult;
			}
			operateResult.IsSuccess = this._serialPort.IsOpen;
			return operateResult;
		}

		public virtual OperateResult Dispose()
		{
			OperateResult operateResult = new OperateResult();
			try
			{
				if (this._serialPort == null)
				{
					operateResult.Message = "please initialize first";
					return operateResult;
				}
				if (this._serialPort.IsOpen)
				{
					this._serialPort.Close();
				}
				operateResult.IsSuccess = true;
				return operateResult;
			}
			catch (Exception ex)
			{
				operateResult.Message = ex.Message;
				return operateResult;
			}
		}

		public static string[] GetPorts()
		{
			return SerialPort.GetPortNames();
		}

		protected virtual OperateResult Write(byte[] sendData)
		{
			OperateResult operateResult = new OperateResult();
			if (!this.IsPortValid.IsSuccess)
			{
				operateResult.Message = this.IsPortValid.Message;
				return operateResult;
			}
			try
			{
				this._serialPort.DiscardOutBuffer();
				this._serialPort.DiscardInBuffer();
				this._serialPort.Write(sendData, 0, sendData.Length);
				operateResult.IsSuccess = true;
				return operateResult;
			}
			catch (Exception ex)
			{
				operateResult.Message = ex.Message;
				return operateResult;
			}
		}

		protected virtual OperateResult<byte[]> Read(int interval = 30)
		{
			OperateResult<byte[]> operateResult = new OperateResult<byte[]>();
			if (!this.IsPortValid.IsSuccess)
			{
				operateResult.Message = this.IsPortValid.Message;
				return operateResult;
			}
			List<byte> list = new List<byte>();
			try
			{
				while (this._serialPort.BytesToRead > 0)
				{
					byte[] array = new byte[this._serialPort.BytesToRead];
					this._serialPort.Read(array, 0, array.Length);
					list.AddRange(array);
					Thread.Sleep(interval);
				}
				this._serialPort.DiscardOutBuffer();
				this._serialPort.DiscardInBuffer();
				operateResult.IsSuccess = list.Count > 0;
				operateResult.Content = list.ToArray();
				return operateResult;
			}
			catch (Exception ex)
			{
				operateResult.Message = ex.Message;
				return operateResult;
			}
		}

		protected virtual OperateResult<byte[]> ReadAfterWrite(byte[] sendData, int readInterval = 30)
		{
			if (sendData == null)
			{
				throw new ArgumentNullException("sendData");
			}
			OperateResult<byte[]> operateResult = new OperateResult<byte[]>();
			if (sendData.Length == 0)
			{
				operateResult.Message = "send count=0";
				return operateResult;
			}
			OperateResult operateResult2 = this.Write(sendData);
			if (!operateResult2.IsSuccess)
			{
				operateResult.Message = operateResult2.Message;
				return operateResult;
			}
			return this.Read(readInterval);
		}
	}
}
